package cn.bbstone.pisces2.comm.codec;

import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.bbstone.pisces2.comm.Const;
import cn.bbstone.pisces2.proto.req.ReqFile;
import cn.bbstone.pisces2.proto.req.ReqFileData;
import cn.bbstone.pisces2.proto.req.ReqFileDataAck;
import cn.bbstone.pisces2.proto.req.ReqFileInfo;
import cn.bbstone.pisces2.proto.req.ReqFileInfoAck;
import cn.bbstone.pisces2.proto.req.ReqFileInfoSkipAck;
import cn.bbstone.pisces2.proto.req.ReqListData;
import cn.bbstone.pisces2.proto.req.ReqListDataAck;
import cn.bbstone.pisces2.proto.req.ReqListInfo;
import cn.bbstone.pisces2.proto.req.ReqListInfoAck;
import cn.bbstone.pisces2.util.BByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;

public class ReqFileDecoder {
	private static Logger log = LoggerFactory.getLogger(ReqFileDecoder.class);
	
    public ReqFileDecoder() {
    }

    public ReqFile decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
        // magic + msgType = 8B
        if (byteBuf.readableBytes() < Const.HEAD_LEN_REQ_FILE) {
            log.error("decode msg error, header length incorrect. expected {}, but it is: {}",
                    Const.HEAD_LEN_REQ_FILE, byteBuf.readableBytes());
            return null;
        }
        // msg not start with BBSTONE, will be abandon
        byte[] magicBytes = new byte[7];
        byteBuf.getBytes(0, magicBytes);
        String magic = BByteUtil.toStr(magicBytes);
        if (!Const.magic.equals(magic)) {
            log.error("msg not support.");
            return null;
        }
        // get msgType
        Byte msgType = byteBuf.getByte(7);
        ReqFile reqFile = reqFile = parseMsg(byteBuf);
        if (reqFile != null) {
            switch (msgType) {
                case 0x01: // BFileCmd.REQ_LIST_INFO
                    ReqListInfo reqListInfo = new ReqListInfo();
                    BeanUtils.copyProperties(reqListInfo, reqFile);
//                    list.add(reqListInfo);
                    return reqListInfo;
//                    break;
                case 0x11: // BFileCmd.REQ_LIST_DATA
                    ReqListData reqListData = new ReqListData();
                    BeanUtils.copyProperties(reqListData, reqFile);
//                    list.add(reqListData);
//                    break;
                    return reqListData;
                case 0x02: // REQ_FILE_INFO
                    ReqFileInfo reqFileInfo = new ReqFileInfo();
                    BeanUtils.copyProperties(reqFileInfo, reqFile);
//                    list.add(reqFileInfo);
//                    break;
                    return reqFileInfo;
                case 0x07: // REQ_FILE_DATA
                    ReqFileData reqFileData = new ReqFileData();
                    BeanUtils.copyProperties(reqFileData, reqFile);
//                    list.add(reqFileData);
//                    break;
                    return reqFileData;
                case 0x61: // REQ_LIST_INFO_ACK
                    ReqListInfoAck reqListInfoAck = new ReqListInfoAck();
                    BeanUtils.copyProperties(reqListInfoAck, reqFile);
//                    list.add(reqListInfoAck);
//                    break;
                    return reqListInfoAck;
                case 0x64: // REQ_LIST_DATA_ACK
                    ReqListDataAck reqListDataAck = new ReqListDataAck();
                    BeanUtils.copyProperties(reqListDataAck, reqFile);
//                    list.add(reqListInfoAck);
//                    break;
                    return reqListDataAck;
                case 0x62: // REQ_FILE_INFO_ACK
                    ReqFileInfoAck reqFileInfoAck = new ReqFileInfoAck();
                    BeanUtils.copyProperties(reqFileInfoAck, reqFile);
//                    list.add(reqFileInfoAck);
//                    break;
                    return reqFileInfoAck;
                case 0x65: // REQ_FILE_INFO_SKIP_ACK
                    ReqFileInfoSkipAck reqFileInfoSkipAck = new ReqFileInfoSkipAck();
                    BeanUtils.copyProperties(reqFileInfoSkipAck, reqFile);
//                    list.add(reqFileInfoAck);
//                    break;
                    return reqFileInfoSkipAck;
                case 0x63: // REQ_FILE_DATA_ACK
                    ReqFileDataAck reqFileDataAck = new ReqFileDataAck();
                    BeanUtils.copyProperties(reqFileDataAck, reqFile);
//                    list.add(reqFileDataAck);
//                    break;
                    return reqFileDataAck;
                default:

            }
        }
        return null;
    }

    private ReqFile parseMsg(ByteBuf msg) {
        // skip magic
        msg.skipBytes(7);
        // msgType
        Byte msgType = msg.readByte();
        // msgId
        byte[] msgIdBytes = new byte[32];
        msg.readBytes(msgIdBytes);
        String msgId = BByteUtil.toStr(msgIdBytes);
        // reqTs
        long reqTs = msg.readLong();
        // fileNo
        long fileNo = msg.readLong();
        // bodyLen
        Short bodyLen = msg.readShort();
        // bodyData
        if (bodyLen != 0)
            log.warn("the ack msg should not contains body.");
        byte[] bodyBytes = new byte[0];
        // build model
        ReqFile reqFile = new ReqFile();
        reqFile.setMsgType(msgType);
        reqFile.setMsgId(msgId);
        reqFile.setReqTs(reqTs);
        reqFile.setFileNo(fileNo);
        reqFile.setBodyLen(bodyLen);
        reqFile.setBodyData(bodyBytes);
        //
        return reqFile;
    }
}
